#include "Loggers.h"
#include <chrono>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <errno.h>
#include "include/ConfigJson.h"
#include "include/BlockQueue.h"
#include "include/MemoryPool.h"
#include <shared_mutex>

namespace Tool
{

struct FileInfo
{
    bool m_first = true;
    std::atomic<int> m_count = 0;
    std::ofstream    m_file;
};

const std::vector<std::string> levelString = {
    "debug",
    "info",
    "warning",
    "error"
};

const std::string RESET = "\033[0m";
const std::string RED = "\033[31m";
const std::string YELLOW = "\033[33m";
const size_t BUF_SIZE = 8192;
const size_t HEADER_SIZE = 5;
const size_t LOGER_NAME_MAX_LEN = 64;        // 日志名最大长度（避免越界）
const size_t CONTENT_MAX_SIZE = BUF_SIZE - HEADER_SIZE - LOGER_NAME_MAX_LEN;  // 内容区=总大小-头部-日志名区
using LogMemPool = MemoryPool<char[BUF_SIZE], 2000>;

struct Loggers::LoggersPrivater
{
    bool m_isInitialized = false;
    std::string m_logPath = "./logs";          // 日志目录（配置读取）
    std::string m_logFileName = ".log";        // 日志后缀（配置读取）
    std::string m_totalName = "total";         // Total汇总日志名（配置读取）
    int m_splitLines = 500000;                 // 日志切割阈值（配置读取）
    LogLevel m_logLevel = LogLevel::Debug;     // 日志级别（配置读取）
    bool m_outputToConsole = true;             // 控制台输出（配置读取）

    std::unique_ptr<LogMemPool> m_memoryPool;  // 内存池
    BlockQueue<char*> m_queue;                 // 全局阻塞队列（原有逻辑保留）
    std::unordered_map<std::string, FileInfo> m_logFiles;  // 多文件映射表
    std::thread m_asyncThread;                 // 异步写入线程
    std::atomic<bool> m_isRunning = false;     // 运行状态标记
    std::shared_mutex m_filesMutex;            // 多文件映射表的读写锁
};

Loggers::Loggers() : m_privater(new LoggersPrivater)
{
    ConfigJson config;
    try
    {
        config.Load("config.json");
        m_privater->m_logPath = config.GetValue("Log", "logPath", "logs").ToString();
        m_privater->m_logFileName = config.GetValue("Log", "logAkhiranName", ".log").ToString();
        m_privater->m_totalName = config.GetValue("Log", "totalName", "total").ToString();
        m_privater->m_outputToConsole = config.GetValue("Log", "outputToConsole", true);
        m_privater->m_logLevel = static_cast<LogLevel>(config.GetValue("Log", "level", 0).ToInt());
        m_privater->m_splitLines = config.GetValue("Log", "splitLines", 500000);

        Init();
        config.Save("config.json");
    }
    catch (const std::bad_variant_access& e)
    {
        std::cerr << "Config read failed: " << e.what() << ", use default" << std::endl;
        Init();
    }
}

Loggers::~Loggers()
{
    UnInit();
    if (m_privater)
    {
        delete m_privater;
        m_privater = nullptr;
    }
}

bool Loggers::Init()
{
    if (m_privater->m_isInitialized)
    {
        std::cerr << "Loggers already initialized" << std::endl;
        return false;
    }

    if (!std::filesystem::exists(m_privater->m_logPath))
    {
        if (!std::filesystem::create_directories(m_privater->m_logPath))
        {
            std::cerr << "Create log dir failed: " << m_privater->m_logPath << ", " << strerror(errno) << std::endl;
            return false;
        }
    }

    m_privater->m_isRunning = true;
    m_privater->m_asyncThread = std::thread(&Loggers::AsyncWriteLog, this);
    m_privater->m_memoryPool = std::make_unique<LogMemPool>();
    m_privater->m_isInitialized = true;
    return true;
}

void Loggers::UnInit()
{
    m_privater->m_isRunning = false;
    m_privater->m_queue.Stop();

    if (m_privater->m_asyncThread.joinable())
    {
        m_privater->m_asyncThread.join();
    }

    {
        std::shared_lock<std::shared_mutex> lock(m_privater->m_filesMutex);
        for (auto& [name, fileInfo] : m_privater->m_logFiles)
        {
            if (fileInfo.m_file.is_open())
            {
                fileInfo.m_file.close();
            }
        }
    }
    m_privater->m_logFiles.clear();
    m_privater->m_isInitialized = false;
}

void Loggers::Write(const char* fileName, int lineNumber, LogLevel level, std::string logerName, const char* format, ...)
{
    if (!m_privater->m_isInitialized || level < m_privater->m_logLevel)
    {
        return;
    }

    char (*logBuf)[BUF_SIZE] = m_privater->m_memoryPool->allocate();
    if (!logBuf)
    {
        std::cerr << "Memory pool allocate failed, skip log" << std::endl;
        return;
    }

    int level_index = static_cast<int>(level);
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    std::tm tm = {};
#if defined(_WIN32) || defined(_WIN64)
    localtime_s(&tm, &time);
#else
    localtime_r(&time, &tm);
#endif
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::string path = fileName;
    static std::unordered_map<std::string, std::string> fileNameCache;
    static std::shared_mutex cacheMutex; // 加读写锁
    {
        std::shared_lock<std::shared_mutex> readLock(cacheMutex); // 读用共享锁
        auto it = fileNameCache.find(fileName);
        if (it != fileNameCache.end())
        {
            path = it->second;
        }
        else
        {
            path = fileName;
            size_t last_pos = path.find_last_of("/\\");
            if (last_pos != std::string::npos)
            {
                path = path.substr(last_pos + 1);
            }
            last_pos = path.find_last_of(".");
            if (last_pos != std::string::npos)
            {
                path = path.substr(0, last_pos);
            }
            fileNameCache[fileName] = path;
        }
    }

    char* header_end = *logBuf + HEADER_SIZE;                  // 头部结束地址（第5字节后）
    char* name_start = header_end;                             // 日志名起始地址
    char* content_start = name_start + LOGER_NAME_MAX_LEN;     // 日志内容起始地址

    strncpy(name_start, logerName.c_str(), LOGER_NAME_MAX_LEN - 1);
    name_start[LOGER_NAME_MAX_LEN - 1] = '\0';

    va_list args;
    va_start(args, format);
    int content_len = std::snprintf(content_start, CONTENT_MAX_SIZE,
                                    "[%04d-%02d-%02d %02d:%02d:%02d.%03lld %s:%d] [%s] ",
                                    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
                                    tm.tm_hour, tm.tm_min, tm.tm_sec, ms.count(),
                                    path.c_str(), lineNumber, levelString[level_index].c_str());
    content_len += std::vsnprintf(content_start + content_len, CONTENT_MAX_SIZE - content_len, format, args);
    va_end(args);

    *reinterpret_cast<int*>(*logBuf) = content_len;  // 内容长度（不含头部和日志名）
    (*logBuf)[4] = static_cast<char>(level);         // 日志级别

    m_privater->m_queue.Push(*logBuf);
}

void Loggers::SetOutputToConsole(bool output)
{
    std::unique_lock<std::shared_mutex> lock(m_privater->m_filesMutex);
    m_privater->m_outputToConsole = output;
}

void Loggers::SetLevel(LogLevel level)
{
    std::unique_lock<std::shared_mutex> lock(m_privater->m_filesMutex);
    m_privater->m_logLevel = level;
}

void Loggers::AsyncWriteLog()
{
    while (m_privater->m_isRunning || !m_privater->m_queue.IsEmpty())
    {
        char* logBuf = m_privater->m_queue.Pop();
        if (!logBuf)
        {
            continue;
        }

        int content_len = *reinterpret_cast<int*>(logBuf);              // 内容长度
        const char* logerName = logBuf + HEADER_SIZE;                   // 日志名（第5字节开始）
        const char* content_start = logerName + LOGER_NAME_MAX_LEN;     // 内容起始地址
        WriteToSingleFile(logerName, m_privater->m_logFiles[logerName], content_start, content_len);
        WriteToSingleFile(m_privater->m_totalName, m_privater->m_logFiles[m_privater->m_totalName], content_start, content_len);

        if (m_privater->m_outputToConsole)
        {
#ifdef __linux__
            LogLevel level = static_cast<LogLevel>(logBuf[4]);
            if (level == LogLevel::Warning)
            {
                std::cout << YELLOW;
                std::cout.write(content_start, content_len);
                std::cout << RESET << '\n';
            }
            else if (level == LogLevel::Error)
            {
                std::cout << RED;
                std::cout.write(content_start, content_len);
                std::cout << RESET << '\n';
            }
            else
            {
                std::cout.write(content_start, content_len);
                std::cout.put('\n');
            }
#else
            std::cout.write(content_start, content_len);
            std::cout.put('\n');
#endif
        }
        m_privater->m_memoryPool->deallocate(reinterpret_cast<char(*)[BUF_SIZE]>(logBuf));
    }
}

void Loggers::WriteToSingleFile(const std::string& logerName,FileInfo& fileInfo, const char* content, int contentLen)
{
    if(fileInfo.m_first)
    {
        fileInfo.m_file.open(GetLogFileName(logerName), std::ios::app);
        fileInfo.m_first = false;
    }
    fileInfo.m_file.write(content, contentLen);
    fileInfo.m_file.put('\n');
    if (++fileInfo.m_count >= m_privater->m_splitLines)
    {
        fileInfo.m_file.flush();
        fileInfo.m_file.close();
        fileInfo.m_file.open(GetLogFileName(logerName), std::ios::app);
        fileInfo.m_count = 0;
    }
}

std::string Loggers::GetLogFileName(const std::string& logerName)
{
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
    std::tm tm = {};
#if defined(_WIN32) || defined(_WIN64)
    localtime_s(&tm, &time);
#else
    localtime_r(&time, &tm);
#endif

    std::ostringstream oss;
    oss << m_privater->m_logPath << "/"
        << logerName << "_"
        << std::put_time(&tm, "%Y%m%dT%H%M%S")
        << std::setw(3) << std::setfill('0') << ms.count()  // 毫秒级时间戳，避免文件名冲突
        << m_privater->m_logFileName;
    return oss.str();
}

}  // namespace Tool
